package com.eshop.modules.security.security;

import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import java.util.Base64;
import javax.servlet.http.HttpServletRequest;
import com.eshop.modules.security.security.vo.JwtUser;
import com.google.gson.Gson;
import com.eshop.utils.StringUtils;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;
import io.jsonwebtoken.Jwts;
import java.util.Date;
import io.jsonwebtoken.Claims;
import com.eshop.utils.RedisUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import com.eshop.modules.security.config.SecurityProperties;
import org.springframework.stereotype.Component;

@Component
public class TokenUtil
{
    @Autowired
    private SecurityProperties properties;
    protected static final Logger LOGGER;
    private static final String REDIS_PREFIX_AUTH = "auth:";
    private static final String REDIS_PREFIX_USER = "user-details:";
    @Autowired
    private RedisUtils redisUtils;
    
    public String getUsernameFromToken(final String token) {
        final Claims claims = this.getClaimsFromToken(token);
        return (claims != null) ? claims.getSubject() : null;
    }
    
    public Date getExpiredFromToken(final String token) {
        final Claims claims = this.getClaimsFromToken(token);
        return (claims != null) ? claims.getExpiration() : null;
    }
    
    private Claims getClaimsFromToken(final String token) {
        Claims claims;
        try {
            claims = (Claims)Jwts.parser().setSigningKey(this.properties.getSecret()).parseClaimsJws(token).getBody();
        }
        catch (Exception e) {
            TokenUtil.LOGGER.warn("getClaimsFromToken exception", (Throwable)e);
            claims = null;
        }
        return claims;
    }
    
    private Date generateExpired() {
        return new Date(System.currentTimeMillis() + this.properties.getTokenValidityInSeconds() * 1000L);
    }
    
    private Boolean isTokenExpired(final String token) {
        final Date expirationDate = this.getExpiredFromToken(token);
        return expirationDate.before(new Date());
    }
    
    public String generateToken(final UserDetails userDetails) {
        final String secret = this.properties.getSecret();
        final String token = Jwts.builder().setSubject(userDetails.getUsername()).setExpiration(this.generateExpired()).signWith(SignatureAlgorithm.HS512, secret).compact();
        final String key = "auth:" + userDetails.getUsername() + ":" + token;
        this.redisUtils.set(key, token, this.properties.getTokenValidityInSeconds() / 1000L);
        this.putUserDetails(userDetails);
        return token;
    }
    
    public Boolean validateToken(final String token) {
        final String username = this.getUsernameFromToken(token);
        final String key = "auth:" + username + ":" + token;
        final Object data = this.redisUtils.get(key);
        final String redisToken = (data == null) ? null : data.toString();
        return StringUtils.isNotEmpty((CharSequence)token) && !this.isTokenExpired(token) && token.equals(redisToken);
    }
    
    public void removeToken(final String token) {
        final String username = this.getUsernameFromToken(token);
        final String key = "auth:" + username + ":" + token;
        this.redisUtils.del(new String[] { key });
        this.delUserDetails(username);
    }
    
    protected String getUserDetailsString(final String token) {
        final String username = this.getUsernameFromToken(token);
        final String key = "user-details:" + username;
        final Object data = this.redisUtils.get(key);
        return (data == null) ? null : data.toString();
    }
    
    public UserDetails getUserDetails(final String token) {
        final String userDetailsString = this.getUserDetailsString(token);
        if (userDetailsString != null) {
            return (UserDetails)new Gson().fromJson(userDetailsString, (Class)JwtUser.class);
        }
        return null;
    }
    
    private void putUserDetails(final UserDetails userDetails) {
        final String key = "user-details:" + userDetails.getUsername();
        this.redisUtils.set(key, new Gson().toJson(userDetails), this.properties.getTokenValidityInSeconds() / 1000L);
    }
    
    private void delUserDetails(final String username) {
        final String key = "user-details:" + username;
        this.redisUtils.del(new String[] { key });
    }
    
    public String getToken(final HttpServletRequest request) {
        final String requestHeader = request.getHeader(this.properties.getHeader());
        if (requestHeader != null && requestHeader.startsWith(this.properties.getTokenStartWith())) {
            return requestHeader.substring(7);
        }
        return null;
    }
    
    public static void main(final String[] args) {
        final String key = Base64.getEncoder().encodeToString("123".getBytes());
        final Claims claims = (Claims)Jwts.parser().setSigningKey(key).parseClaimsJws("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFwcCIsIndyaXRlIl0sInVpbiI6MSwiZXhwIjoxNTc1MDE1ODgzLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiYjdiYjQ1NTQtNTQ4OS00YTg5LWI3NjQtNzNjODI0YzljNGMyIiwiY2xpZW50X2lkIjoibHZoYWliYW8ifQ.x7QZxRAR1wuX_YNLi6EzRJ1iaKr1rIEUgjtYF0oSx5k").getBody();
        System.out.println(JSON.toJSONString(claims));
    }
    
    static {
        LOGGER = LoggerFactory.getLogger((Class)TokenUtil.class);
    }
}
